/**
 * @file mmgr_modem.c
 * @brief 
 * @author  ()
 * @version 1.0
 * @date 2024-09-13
 * 
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-13 <td>1.0     <td>     <td>内容
 * </table>
 */
#include "global.h"
#include "bsp_modem.h"
#include "include/mmgr_log.h"
#include "include/mmgr_file.h"
#include "include/mmgr_modem.h"
#include "include/mmgr_misc.h"
#include "include/mmgr_wifi.h"
#include "service/include/swei_cert.h"
#include "flash/key_params/key_params.h"
#include "include/mmgr_pdp.h"
#include "include/mmgr_sim.h"
#include "modem/qlmodem/task_modem.h"
#include "service/include/swei_socket.h"
#include "utils/utils_timer.h"
#include "misc/misc_system.h"

/* 宏定义----------------------------------------------------------------- */
#define TASK_NAME_MMGR  "MMGR"

/* 结构体及函数声明----------------------------------------------------------------- */
extern int8_t save_quec_imei(char *imei);
bool qlsdk_unlock_present_block(void);
static void mmgr_modem_enable(void);
static void task_modem_upd_cb(mdm_upd_id id, int prm, void *data, size_t size);
void mmgr_imei_set(char *imei);

/* 全局变量声明----------------------------------------------------------------- */
static struct mmgr_cps _cps = {
    .is_force_close     = false,
    .version            = {0},
    .iccid              = {0},
    .imei               = {0},
    .imsi               = {0},
    .prm_read_timing    = NOTIMING,
    .status             = POWEROFF,
};
static struct mmgr_cps *mmgr_cps    = &_cps;
static struct mdm_base_prm base_prm = {0};
bool modem_sim_is_existing          = false;                        /* modem模块是否插入了SIM卡 */

/* 函数实现----------------------------------------------------------------- */
/*
 * @brief modem 引脚适配接口
 */
const struct modem_pins pins = {
    .power_on       = bsp_modem_powerctrl_on,
    .power_off      = bsp_modem_powerctrl_off,
    .ring_pin_get   = bsp_modem_ring_get,
    .dtr_pin_set    = bsp_modem_dtr_set,
    .pwron_pin_set  = bsp_modem_powerkey,
    .status_pin_get = NULL,//bsp_modem_status_get(),
};

/*
 * @brief modem 串口驱动适配接口
 */
const struct modem_uart uart = {
    .read           = bsp_modem_read,
    .write          = bsp_modem_write,
    .set_baudrate   = bsp_modem_set_baudrate,
};

const struct modem_mgr mmgr = {
    .unlock_present_block = qlsdk_unlock_present_block,
};

/*
 * @brief 是否解除当前的由于异常引起的阻塞
 */
bool  qlsdk_unlock_present_block(void)
{
    return false;
}

/*
 * @brief 手动注册使能判断
 */
bool opr_manual_mgr_enable(void)
{
    return true;
}

/*
 * @brief mmgr 初始化
 */
void mmgr_modem_init(void)
{
    qltask_modem_fw_encryption_update();
    mmgr_modem_enable();                                    /* 使能 SDK MODEM 任务 */
}

/*
 * @brief 使能 SDK MODEM 任务接口
 */
static void mmgr_modem_enable(void)
{
    int32_t result = 0;

    struct network_config network = {0};

    if (POWERON == mmgr_cps->status)
        return ;

    mmgr_cps->status = PWRON_ING;

    /* 设置网络制式(客户没有配置, 默认为auto模式) */
    network.network[0]  = NET_AUTO,
    network.net_cnt     = 1,
    result = qltask_modem_ioctl(MDM_CFG_NET ,&network);
    if (0 != result)
        log_e("Modem network mode config fail, result = %d.\r\n", result);

    /* 设置扫描间隔 */
    result = qltask_modem_ioctl(MDM_GET_BASE_PRM, &base_prm);
    if (0 == result) {
        base_prm.net_check_inr  = 180;                      /* 调整查询间隔和心跳包一致 */
        base_prm.sock_check_inr = 180;
        base_prm.nb_cell_en     = true;                     /* 使能临近小区搜索功能 */
        base_prm.nb_cell_inr    = 1;
        base_prm.tmp_blacklist_mgr.mode = 3;                /* 使能临时黑名单功能 */
        base_prm.tmp_blacklist_mgr.ping_ipaddr = "time.windows.com";
        result = qltask_modem_ioctl(MDM_BASE_PRM, &base_prm);
        if (0 != result)
            log_e("Modem base prm config fail, result = %d\r\n", result);
    }

    /* 清除dataRetry计数 */
    qltask_modem_manual_socket_nfm_clear();

    /* 配置modem为AT指令执行结束后休眠 */
    if (0 != qltask_modem_start(ATCMD_SLEEP)) {
        log_e("The module failed to start and will be retried.\r\n");
        return;
    }

    mmgr_cps->status = POWERON;
    qltask_modem_subscribe_upd(task_modem_upd_cb);          /* 订阅 SDK MODEM 事件 */
}

/*
 * @brief 失能 SDK MODEM 任务接口
 */
void mmgr_modem_disable(void)
{
    if (POWEROFF == mmgr_cps->status)
        return;

    modem_trace(LOG_INFO "Request modem disable\r\n");

    mmgr_cps->status = PWROFF_ING;
    qltask_modem_delete();
    mmgr_cps->status = POWEROFF;
    mmgr_cps->is_read_ok = false;
}

/*
 * @brief SDK modem 定时查询参数设置
 */
static void mmgr_modem_prm_manage(void)
{
    static work_mode_e last_mode = WORK_MODE_NORMAL;
    int32_t result = 0;

    if (last_mode == misc_get_work_mode())
        return;

    last_mode = misc_get_work_mode();

    /* 休眠模式下, 定时查询间隔调大 */
    if (WORK_MODE_SLEEP == last_mode) {
        base_prm.net_check_inr  = 1800;
        base_prm.sock_check_inr = 1800;
    }
    else {
        base_prm.net_check_inr  = 180;                      /* 调整查询间隔和心跳包一致 */
        base_prm.sock_check_inr = 180;
    }

    result = qltask_modem_ioctl(MDM_BASE_PRM, &base_prm);
    if (0 != result)
        log_e("Modem base prm config fail, result = %d\r\n", result);
}

/*
 * @brief 网络校时事件回调处理
 */
static void mmgr_network_time_update(int prm, void *data, size_t size)
{
    struct tm _utc = {0};
    net_time_t *time = NULL;
    time_t timestamp = 0;

    if (size != sizeof(net_time_t)) 
        return;

    time = (net_time_t *)data;

    /* UTC时间有效并且时区也有效, 则更新 */
    if (!time->utc_valid || !time->tz_valid)
        return;

    if (TIME_SRC_NTP == (int)prm) {                     //UTC, TIMEZONE
        _utc = time->utc;
    }
    else if (TIME_SRC_NITZ == (int)prm) {               //RTC, TIMEZONE
        /* NITZ的时间已经是加过时区的了, 所以这里需要减去时区获取到UTC时间 */
        timestamp = mktime(&time->utc);
        timestamp -= (time->tz * 15 * 60);              //RTC second -> UTC second
        _utc = *localtime(&timestamp);
    }

    modem_utc_update_rtc_time(&_utc, time->tz);
    modem_trace(LOG_INFO "update network time, src:%d, tz:%d, %d/%d/%d,%02d:%02d:%02d\r\n", 
                                    prm, time->tz,
                                    time->utc.tm_year+1900, time->utc.tm_mon+1,
                                    time->utc.tm_mday, time->utc.tm_hour,
                                    time->utc.tm_min, time->utc.tm_sec);
}

/// @brief modem 更新事件上报
/// @param id 
/// @param prm 
/// @param data 
/// @param size 
static void task_modem_upd_cb(mdm_upd_id id, int prm, void *data, size_t size)
{
    log_d("task_modem_upd_cb event = %d\r\n", id);

    switch(id) {
        case UPD_MDM_VALID:     /* MODEM 通讯状态事件 */
            if (true == (bool)prm) {
                log_d("modem communicate normal\r\n");
            } else {
                log_e("modem communicate error\r\n");
            }
            break;

        case UPD_MDM_RDY:       /* MODEM 准备完成事件 */
            /* 清除相关信息 */
            mmgr_misc_free();

            if (0 == qltask_modem_ioctl(MDM_GET_VER, mmgr_cps->version)) {
                log_d("modem version: %s\r\n",mmgr_cps->version);
            }

            if (0 == qltask_modem_ioctl(MDM_GET_SUB_VER, mmgr_cps->sub_version)) {
                log_d("modem sub version: %s\r\n",mmgr_cps->sub_version);
            }

            if (0 == qltask_modem_ioctl(MDM_GET_IMEI, mmgr_cps->imei)) {
                save_quec_imei(mmgr_cps->imei); // TODO:write imei to 1sector
                mmgr_imei_set(mmgr_cps->imei);
                log_d("modem imei: %s\r\n",mmgr_cps->imei);
            }
            break;

        case UPD_MDM_SIM_RDY:   /* MODEM SIM准备完成事件 */
            if (0 == qltask_modem_ioctl(MDM_GET_ICCID, mmgr_cps->iccid)) {
                log_d("modem iccid: %s\r\n",mmgr_cps->iccid);
            }

            if (0 == qltask_modem_ioctl(MDM_GET_IMSI, mmgr_cps->imsi)) {
                log_d("modem imsi: %s\r\n",mmgr_cps->imsi);
            }

            if (tbox_dqa_mode_get()) {
                mmgr_modem_disable();
                log_d("in dqa mode, modem msg read end, and close modem\r\n");
            }
            mmgr_cps->is_read_ok = true;    /* 通讯正常 */
            log_d("modem ready, can perform other actions\r\n");
            break;

        case UPD_SOC_STAT:
            log_d("The %s task receives an UPD_SOC_STAT event.STATUS:%d.\r\n", TASK_NAME_MMGR, (int)data);
            swei_socket_update(M_SOC_STAT, prm, data, size);
            break;

        case UPD_NET_STAT:
            log_d("The %s task receives an UPD_NET_STAT event.NETREG:%d, NET:%d.\r\n", \
                                                                    TASK_NAME_MMGR, (int)prm, (int)data);
            mmgr_netreg_update(prm, data, size);
            break;

        case UPD_NET_TIME:
            mmgr_network_time_update(prm, data, size);
            break;

        case UPD_SIM_STAT:
        	log_d("The %s task receives an UPD_SIM_STAT event.prm=%d data=%d size=%d\r\n", TASK_NAME_MMGR, prm, (int)data, size);
        	// modem_set_first_lose_time(getsec());

        	if((mdm_sim_stat)prm == SIM_LOST) {
        		log_i("The sim card is lost\r\n");
        		modem_sim_is_existing = false;
        	}
        	else if((mdm_sim_stat)prm == SIM_EXISTING) {
        		modem_sim_is_existing = true;
        		log_i("The sim card is exist\r\n");
        	}
        	else if((mdm_sim_stat)prm == SIM_NEED_PIN) {
        		modem_sim_is_existing = true;
        		log_i("The sim card is exist, need PIN code\r\n");
        	}
        	else if((mdm_sim_stat)prm == SIM_NEED_PUK) {
        		modem_sim_is_existing = true;
        		log_i("The sim card is exist, need PUK code\r\n");
        	}
        	else {
        		log_i("The sim card is unknown\r\n");
        		modem_sim_is_existing = false;
        	}

        	if((mdm_sim_stat)prm == SIM_LOST) {
        		mmgr_simcard_set_lost(true);
        	} else {
        		mmgr_simcard_set_lost(false);
        	}
        	break;

        case UPD_PDP_STAT:
        	log_d("The %s task receives an UPD_PDP_STAT event.prm=%d data=%d size=%d\r\n", TASK_NAME_MMGR, prm, (int)data, size);
        	if(prm == PDP_INACTIVED) {
                log_i(" The pdp inactived\r\n");
                // prot_ncn_rpt_set(PROT_NCN_RPT_PDPLOST);
                log_i("current modem status = %d\r\n",mmgr_cps->status);
                if (mmgr_cps->status != POWEROFF)
                    mmgr_pdp_set_active(false);
            }
            else if(prm == PDP_ACTIVATED) {
                log_i(" The pdp activated\r\n");
                mmgr_pdp_set_active(true);
            }
        	break;

        case UPD_FILE_STAT:
            log_d("The %s task receives an UPD_FILE_STAT event.prm=%d data=%s size=%d\r\n", TASK_NAME_MMGR, prm, (char*)data, size);
            swei_cert_status_update(prm, data, size);
            break;

        case UPD_WIFI_SCAN: {
            struct wifi_info *info = (struct wifi_info *) data;
            if (prm > 0 && info) {
                log_d("The %s task receives an UPD_WIFI_SCAN event.prm=%d data={%d,%.17s}\r\n\0", TASK_NAME_MMGR, prm, info->rssi[0], info->mac[0]);
                mmgr_wifi_count_set(prm);
            }
        }
            break;

        default:
            break;
    }
}

/*
 * @brief   DQA模式下初始化阶段.
 */
void dqa_process(void)
{
    if (0 == mmgr_cps->prm_read_timing)
        mmgr_cps->prm_read_timing = getsec();

    /* DQA模式下数据获取成功, 或者120s超时, 则关闭modem */
    if (mmgr_cps->is_read_ok || timeout_sec(mmgr_cps->prm_read_timing, 120)) {
        mmgr_modem_disable();
    }
}

/*
 * @brief   应用逻辑主循环.
 */
void application_process(void)
{
    mmgr_cps->prm_read_timing = 0;

    mmgr_modem_prm_manage();

    mmgr_modem_enable();

    /* 等待modem准备好 */
    if (mmgr_cps->is_read_ok)
        mmgr_misc_process();                    /* 定时查询信号、注网等信息 */
}

/**
 * @brief 设置IMEI
 * @param  imei             My Param doc
 */
void mmgr_imei_set(char *imei)
{
    taskENTER_CRITICAL();     
    if(imei) 
        strcpy(mmgr_cps->imei, imei);
    taskEXIT_CRITICAL();
}

/**
 * @brief 读取IMEI
 * @return const char* 
 */
const char *mmgr_imei_get(void)
{
    return mmgr_cps->imei;
}

/**
 * @brief 读取iccid
 * @return const char* 
 */
const char *mmgr_iccid_get(void)
{
    return mmgr_cps->iccid;
}

/**
 * @brief 读取iccid
 * @return const char* 
 */
const char *mmgr_imsi_get(void)
{
    return mmgr_cps->imsi;
}

/**
 * @brief 读取modem版本号
 * @return const char* 
 */
const char *mmgr_version_get(void)
{
    return mmgr_cps->version;
}

/**
 * @brief 读取modem子版本号
 * @return const char* 
 */
const char *mmgr_subversion_get(void)
{
    return mmgr_cps->sub_version;
}

/**
 * @brief 读取sim卡状态
 * @return 0:未检测到sim卡 1:sim卡状态正常。 
 */
bool mmgr_simcard_exist_get(void)
{
    return modem_sim_is_existing;
}
